﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Diagnostics;

namespace LowLevelGraphics
{
    /// <summary>
    /// 
    /// </summary>
    [DebuggerDisplay("Start X: {StartX}, End X: {End X}, Y: {Y}, Color: Color")]
    public struct Range : IComparer<Range>, IComparable<Range>

    {
        public int StartX;
        public int EndX;
        public int Y;
        public Color Color;

        public Range(int _nStartX, int _nEndX, int _nY, Color _color)
        {
            StartX = _nStartX;
            EndX = _nEndX;
            Y = _nY;
            Color = _color;
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return string.Format("x1 = {0}, x2 = {1}, y = {2}, Color = {3}", StartX, EndX, Y, Color.ToString());
        }

        /// <summary>
        /// Toes the coordinate string.
        /// </summary>
        /// <returns></returns>
        public string ToCoordinateString()
        {
            return string.Format("x1 = {0}, x2 = {1}, y = {2}", StartX, EndX, Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_range"></param>
        /// <returns></returns>
        public bool Touch(Range _range)
        {
            return false;
        }

        /// <summary>
        /// Gets the length.
        /// </summary>
        /// <value>The length.</value>
        public int Length
        {
            get { return Math.Abs(this.EndX - this.StartX); }
        }

        /// <summary>
        /// Intersectses the specified _range.
        /// </summary>
        /// <param name="_range">The _range.</param>
        /// <returns></returns>
        public bool Intersects(Range _range)
        {
            return (_range.StartX >= StartX && _range.StartX <= EndX)
                //|| (StartX >= _range.StartX && StartX <= _range.EndX);
                && Math.Abs(_range.Y - this.Y)<2;
        }

        /// <summary>
        /// Intersectses the or touches.
        /// </summary>
        /// <param name="_range">The _range.</param>
        /// <returns></returns>
        public bool IntersectsOrTouches(Range _range)
        {
            bool bIntersectsOrTouches = (_range.StartX >= StartX - 1 && _range.StartX <= EndX + 1)
                || (_range.EndX >= StartX - 1 && _range.EndX <= EndX + 1)
                && Math.Abs(_range.Y - this.Y) < 2;
            return bIntersectsOrTouches;
        }

        /// <summary>
        /// Intersections the length.
        /// </summary>
        /// <param name="_range">The _range.</param>
        /// <returns></returns>
        public int IntersectionLength(Range _range)
        {
            int nLength1 = Math.Abs(StartX - EndX);
            int nLength2 = Math.Abs(_range.StartX - _range.EndX);
            int nStart1 = StartX + nLength1;
            int nStart2 = _range.StartX + nLength2;
            return -1;
        }

        /// <summary>
        /// Intersections the range.
        /// </summary>
        /// <param name="_range">The _range.</param>
        /// <returns></returns>
        public Range IntersectionRange(Range _range)
        {
            return Range.Empty;
        }

        /// <summary>
        /// Gets the empty.
        /// </summary>
        /// <value>The empty.</value>
        public static Range Empty
        {
            get { return new Range(); }
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        /// 	<c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj)
        {
            Range range = (Range)obj;
            return (this.StartX == range.StartX 
                && this.EndX == range.EndX 
                && this.Color == range.Color) ;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #region IComparer<Range> Members

        /// <summary>
        /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
        /// </summary>
        /// <param name="x">The first object to compare.</param>
        /// <param name="y">The second object to compare.</param>
        /// <returns>
        /// Value Condition Less than zero<paramref name="x"/> is less than <paramref name="y"/>.Zero<paramref name="x"/> equals <paramref name="y"/>.Greater than zero<paramref name="x"/> is greater than <paramref name="y"/>.
        /// </returns>
        public int Compare(Range x, Range y)
        {
            return x.StartX.CompareTo(y.StartX);
        }

        #endregion

        #region IComparable<Range> Members

        /// <summary>
        /// Compares the current object with another object of the same type.
        /// </summary>
        /// <param name="other">An object to compare with this object.</param>
        /// <returns>
        /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
        /// </returns>
        public int CompareTo(Range other)
        {
            return this.StartX.CompareTo(other.StartX);
        }

        #endregion
    }

    /// <summary>
    /// 
    /// </summary>
    public enum RANGE_COMPARER_MODE
    {
        /// <summary>
        /// 
        /// </summary>
        Y,
        /// <summary>
        /// 
        /// </summary>
        StartX,
        /// <summary>
        /// 
        /// </summary>
        EndX,
        /// <summary>
        /// 
        /// </summary>
        StartX_EndX
    }

    /// <summary>
    /// 
    /// </summary>
    public class RangeComparer : IComparer<Range>
    {
        private RANGE_COMPARER_MODE M_RANGE_COMPARER_MODE = RANGE_COMPARER_MODE.StartX;

        /// <summary>
        /// Initializes a new instance of the <see cref="RangeComparer"/> class.
        /// </summary>
        /// <param name="_MODE">The _ MODE.</param>
        public RangeComparer(RANGE_COMPARER_MODE _MODE)
        {
            M_RANGE_COMPARER_MODE = _MODE;
        }

        #region IComparer<Range> Members

        /// <summary>
        /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
        /// </summary>
        /// <param name="x">The first object to compare.</param>
        /// <param name="y">The second object to compare.</param>
        /// <returns>
        /// Value Condition Less than zero<paramref name="x"/> is less than <paramref name="y"/>.Zero<paramref name="x"/> equals <paramref name="y"/>.Greater than zero<paramref name="x"/> is greater than <paramref name="y"/>.
        /// </returns>
        public int Compare(Range x, Range y)
        {
            int nCompareResult = -10;
            switch (M_RANGE_COMPARER_MODE)
            {
                case RANGE_COMPARER_MODE.EndX:
                    nCompareResult = x.EndX.CompareTo(y.EndX);
                    break;

                case RANGE_COMPARER_MODE.StartX:
                    nCompareResult = x.StartX.CompareTo(y.StartX);
                    break;

                case RANGE_COMPARER_MODE.Y:
                    nCompareResult = x.Y.CompareTo(y.Y);
                    break;

                case RANGE_COMPARER_MODE.StartX_EndX:
                    nCompareResult = x.StartX.CompareTo(y.EndX);
                    break;
            }
            return nCompareResult;
        }

        #endregion
    }
}
